package com.dingup.provider.service.sys.impl;

import com.dingtalk.api.response.*;
import com.dingup.api.Util.PasswordUtil;
import com.dingup.api.adapter.user.SysUserAdapter;
import com.dingup.api.bean.page.PageData;
import com.dingup.api.bean.response.SelectBean;
import com.dingup.api.model.sys.*;
import com.dingup.api.template.message.util.DingTalkUtil;
import com.dingup.provider.cache.DingTalkTaskCache;
import com.dingup.provider.mapper.*;
import com.dingup.provider.service.classInfo.ClassUserInfoService;
import com.dingup.provider.service.sys.SysUserService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by wancheng on 2018/7/23.
 */
@Service
public class SysUserServiceImpl implements SysUserService {

    private static final String DEFAULT_PASSWORD = "dingshang123";
    private static Logger logger = LoggerFactory.getLogger(SysUserServiceImpl.class);
    @Autowired
    DingtalkUserMapper dingtalkUserMapper;
    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    DingtalkRoleMapper dingtalkRoleMapper;
    @Autowired
    SysRoleGroupMapper sysRoleGroupMapper;
    @Autowired
    SysDeptMapper sysDeptMapper;
    @Autowired
    SysUserDeptMapper sysUserDeptMapper;
    @Autowired
    DingtalkUserRoleMapper dingtalkUserRoleMapper;
    @Autowired
    SysRoleMapper sysRoleMapper;
    @Autowired
    SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    ClassUserInfoService classUserInfoService;
    @Autowired
    SysUserSubjectMapper sysUserSubjectMapper;

    @Override
    @Async
    @Transactional
    public String loadByDingTalkUser(String cacheId) {
        //公司token
        String accessToken = DingTalkUtil.getCorpAccessToken();
        logger.info("获取钉钉token" + accessToken);
        //获取此token授权范围
        OapiAuthScopesResponse authScopesResponse = DingTalkUtil.getAuthScopes(accessToken);
        //获取授权部门列表
        List<Long> deptIds = authScopesResponse.getAuthOrgScopes().getAuthedDept();
        //更新员工id集合
        List<String> updateUserId = new ArrayList<>();

        //执行前先清除员工与部门关系
        sysUserDeptMapper.truncateTable();

        for (Long deptId : deptIds) {
            //获取当前部门信息
            logger.info("获取当前部门信息  deptId = {},accessToken={}", deptId, accessToken);
            insertDept(deptId, accessToken);
            //获取当前部门下员工信息
            List<String> deptUserList = insertDeptUserList(deptId, accessToken);
            updateUserId.addAll(deptUserList);
            //获取下属子部门列表
            OapiDepartmentListResponse deptChild = DingTalkUtil.getDepartmentChildList(accessToken, deptId.toString());
            for (OapiDepartmentListResponse.Department child : deptChild.getDepartment()) {
                //部门信息
                insertDept(child.getId(), accessToken);
                //获取部门下员工信息
                List<String> childUserList = insertDeptUserList(child.getId(), accessToken);
                updateUserId.addAll(childUserList);
            }
        }
        loadDingTalkUpdateSysUser(updateUserId);
        DingTalkTaskCache.getInstance().put(cacheId, true);
        return cacheId;
    }

    private List<String> insertDeptUserList(Long deptId, String accessToken) {
        List<String> userIds = new ArrayList<>();
        OapiUserListResponse userResponse = DingTalkUtil.getUserList(accessToken, deptId);
        List<OapiUserListResponse.Userlist> userList = userResponse.getUserlist();
        userList.stream().forEach(
                user -> {
                    userIds.add(user.getUserid());
                    DingtalkUser currentUser = getUser(user);
                    if (dingtalkUserMapper.selectByPrimaryKey(currentUser.getUserId()) == null) {
                        currentUser.setUserPassword(PasswordUtil.encoder(DEFAULT_PASSWORD));
                        dingtalkUserMapper.insertSelective(currentUser);
                    } else {
                        dingtalkUserMapper.updateByPrimaryKeySelective(currentUser);
                    }
                    //员工与部门关联信息
                    SysUserDept userDept = new SysUserDept();
                    userDept.setStatus(true);
                    userDept.setSysDeptId(deptId);
                    userDept.setSysUserId(currentUser.getUserId());
                    sysUserDeptMapper.insertSelective(userDept);
                    logger.info("更新用户与部门: 用户id：{}, 部门id: {}", user.getUserid(), deptId);
                }
        );
        logger.info("更新用户信息:" + userResponse.getBody());
        return userIds;
    }

    private void insertDept(Long deptId, String accessToken) {
        OapiDepartmentGetResponse deptRes = DingTalkUtil.getDeptInfo(deptId, accessToken);
        SysDept dept = new SysDept();
        dept.setName(deptRes.getName());
        dept.setId(deptRes.getId());
        dept.setAutoAddUser(deptRes.getAutoAddUser());
        dept.setCreateDeptGroup(deptRes.getCreateDeptGroup());
        dept.setParentId(deptRes.getParentid());
        dept.setSourceIdentifier(deptRes.getSourceIdentifier());
        dept.setDeptHiding(deptRes.getDeptHiding());
        dept.setDeptManagerUseridList(deptRes.getDeptManagerUseridList());
        dept.setDeptOrder(deptRes.getOrder());
        dept.setDeptPerimits(deptRes.getDeptPerimits());
        dept.setGroupContainSubDept(deptRes.getGroupContainSubDept());
        dept.setDeptManagerUseridList(deptRes.getDeptManagerUseridList());
        dept.setOrgDeptOwner(deptRes.getOrgDeptOwner());
        dept.setOuterPermitDepts(deptRes.getOuterPermitDepts());
        dept.setOuterPermitUsers(deptRes.getOuterPermitUsers());
        if (sysDeptMapper.selectByPrimaryKey(dept.getId()) == null) {
            sysDeptMapper.insertSelective(dept);
        } else {
            sysDeptMapper.updateByPrimaryKeySelective(dept);
        }
        logger.info("更新部门信息:" + deptRes.getBody());
    }

    @Override
    public void loadDingTalkRole() {
        //公司token
        String accessToken = DingTalkUtil.getCorpAccessToken();
        OapiRoleListResponse roleResponse = DingTalkUtil.getRole(accessToken);
        //执行前先清除员工与角色关系
        dingtalkRoleMapper.deleteFromDingtalk();
        for (OapiRoleListResponse.OpenRoleGroup group : roleResponse.getResult().getList()) {
            SysRoleGroup sysRoleGroup = new SysRoleGroup();
            sysRoleGroup.setGroupId(group.getGroupId());
            sysRoleGroup.setName(group.getName());
            if (sysRoleGroupMapper.selectByPrimaryKey(group.getGroupId()) == null) {
                sysRoleGroupMapper.insertSelective(sysRoleGroup);
            } else {
                sysRoleGroupMapper.updateByPrimaryKeySelective(sysRoleGroup);
            }
            for (OapiRoleListResponse.OpenRole role : group.getRoles()) {
                DingtalkRole sysRole = getRole(role, group.getGroupId());
                if (dingtalkRoleMapper.selectByPrimaryKey(role.getId()) == null) {
                    dingtalkRoleMapper.insertSelective(sysRole);
                } else {
                    dingtalkRoleMapper.updateByPrimaryKeySelective(sysRole);
                }
                //员工与角色关系
                OapiRoleSimplelistResponse roleUser = DingTalkUtil.getRoleUserList(role.getId(), accessToken);
                for (OapiRoleSimplelistResponse.OpenEmpSimple user : roleUser.getResult().getList()) {
                    DingtalkUserRole userRole = new DingtalkUserRole();
                    userRole.setCreateTime(new Date());
                    userRole.setStatus(true);
                    userRole.setSysRoleId(role.getId());
                    userRole.setSysUserId(user.getUserid());
                    userRole.setIfFromDingtalk(true);
                    dingtalkUserRoleMapper.insertSelective(userRole);
                    logger.info("更新用户与角色信息: 用户id: {}, 角色id: {}", user.getUserid(), role.getId());
                }
            }
            logger.info("更新角色信息: {}", roleResponse.getBody());
        }
    }

    @Override
    public void loadDingTalkDept() {

    }

    @Override
    public List<SysUser> listAllUser() {
        return sysUserMapper.listAllUser();
    }

    @Override
    public List<SysUser> getUserByDeptId(Long deptId) {
        List<SysUser> users = sysUserMapper.getUserByDeptId(deptId);
        for (SysUser user : users) {
            List<SysRole> roles = sysRoleMapper.getRolesByUserId(user.getUserId());
            user.setRoles(roles);
        }
        return users;
    }

    @Override
    public List<SysUser> getUserByDeptIds(List<Long> deptIds) {
        List<SysUser> users = sysUserMapper.getUserByDeptIds(deptIds);
        for (SysUser user : users) {
            List<SysRole> roles = sysRoleMapper.getRolesByUserId(user.getUserId());
            user.setRoles(roles);
        }
        return users;
    }

    @Override
    public List<String> getUserIdByDeptIds(List<Long> deptIds) {

        List<SysUser> users = getUserByDeptIds(deptIds);

        if (users != null) {
            return users.stream().map(SysUser::getUserId).collect(Collectors.toList());
        }
        return null;

    }

    @Override
    public List<String> getUserIdByDeptIds(Long deptIds) {
        List<Long> ids = new ArrayList<>();
        ids.add(deptIds);
        return getUserIdByDeptIds(ids);
    }

    @Override
    @Transactional
    public Boolean save(SysUser user, Long deptId, List<Integer> roleIds, List<Integer> subjectIds) {
        if (sysUserMapper.insertSelective(user) == 1) {
            SysUserDept sysUserDept = new SysUserDept();
            sysUserDept.setStatus(true);
            sysUserDept.setSysDeptId(deptId);
            sysUserDept.setStatus(false);
            sysUserDept.setSysUserId(user.getUserId());
            sysUserDeptMapper.insertSelective(sysUserDept);
            roleIds.forEach(
                    roleId -> {
                        SysUserRole sysUserRole = new SysUserRole();
                        sysUserRole.setCreateUserId(user.getCreateUserId());
                        sysUserRole.setSysRoleId(roleId);
                        sysUserRole.setSysUserId(user.getUserId());
                        sysUserRole.setCreateTime(new Date());
                        sysUserRoleMapper.insertSelective(sysUserRole);
                    }
            );
            if (!CollectionUtils.isEmpty(subjectIds)) {
                subjectIds.forEach(
                        id -> {
                            SysUserSubject sysUserSubject = new SysUserSubject();
                            sysUserSubject.setSysUserId(user.getUserId());
                            sysUserSubject.setSysSubjectId(id);
                            sysUserSubjectMapper.insertSelective(sysUserSubject);
                        }
                );

            }
            return true;
        }
        return false;
    }

    @Override
    @Transactional
    public String save(SysUser user, Long[] deptId, List<Integer> roleIds) {
        if (sysUserMapper.insertSelective(user) == 1) {
            if (deptId != null){
                Arrays.asList(deptId).forEach(
                        d -> {
                            SysUserDept sysUserDept = new SysUserDept();
                            sysUserDept.setStatus(true);
                            sysUserDept.setSysDeptId(d);
                            sysUserDept.setStatus(false);
                            sysUserDept.setSysUserId(user.getUserId());
                            sysUserDeptMapper.insertSelective(sysUserDept);
                        }
                );
            }
            if (roleIds != null){
                roleIds.forEach(
                        roleId -> {
                            SysUserRole sysUserRole = new SysUserRole();
                            sysUserRole.setCreateUserId(user.getCreateUserId());
                            sysUserRole.setSysRoleId(roleId);
                            sysUserRole.setSysUserId(user.getUserId());
                            sysUserRole.setCreateTime(new Date());
                            sysUserRoleMapper.insertSelective(sysUserRole);
                        }
                );
            }
            return user.getUserId();
        }
        return null;
    }

    @Override
    @Transactional
    public Boolean delete(String userId) {
        if (sysUserMapper.updateIfDeleteByUserId(userId, true) == 1) {
            sysUserDeptMapper.updateIfDeleteByUserId(userId, true);
            sysUserRoleMapper.updateIfDeleteByUserId(userId, true);
            classUserInfoService.deleteUser(userId);
            return true;
        }
        return false;
    }

    @Override
    @Transactional
    public Boolean active(String userId) {
        if (sysUserMapper.updateIfDeleteByUserId(userId, false) == 1) {
            sysUserDeptMapper.updateIfDeleteByUserId(userId, false);
            sysUserRoleMapper.updateIfDeleteByUserId(userId, false);
            return true;
        }
        return false;
    }

    @Override
    public Boolean selectUserIfExistByAccount(String Account) {

        if (sysUserMapper.getByUserAccount(Account) != null) {
            return true;
        }
        return false;
    }

    @Override
    public Boolean selectUserIfExistByEmail(String email) {
        if (sysUserMapper.getByUserEmail(email) != null) {
            return true;
        }
        return false;
    }

    @Override
    public List<SysUserAdapter> getUserByUserNameOrAccount(String query, Boolean ifExternalUser) {
        List<SysUserAdapter> users = sysUserMapper.getUserByUserNameOrAccount(query, ifExternalUser);
        return users;
    }

    @Override
    public void updatePassword(String userAccount, String password) throws Exception {
        SysUser user = sysUserMapper.getByUserAccount(userAccount);
        if (user == null){
            throw new Exception("无此账号");
        }
        SysUser param = new SysUser();
        param.setUserId(user.getUserId());
        param.setUserAccount(userAccount);
        param.setUserPassword(PasswordUtil.encoder(password));
        sysUserMapper.updateByPrimaryKeySelective(param);
    }

    @Override
    public String getUserNameById(String userId) {
        SysUser user = sysUserMapper.getByUserId(userId);
        return user.getUserName();
    }

    @Override
    public List<SelectBean> getAllUserNameAndUserIds() {
        List<SysUser> users = sysUserMapper.getAllUserNameAndUserIds(null);
        List<SelectBean> res = users.stream().map(u -> {
            String accountEnd = u.getUserAccount();
            if (StringUtils.isNotEmpty(accountEnd) && accountEnd.length() > 4) {
                accountEnd = accountEnd.substring(accountEnd.length() - 4, accountEnd.length());
            }
            return new SelectBean(u.getUserName() + " " + accountEnd, u.getUserId());
        }).collect(Collectors.toList());
        return res;
    }

    @Override
    public List<SelectBean> getUserFromSysten() {
        List<SysUser> users = sysUserMapper.getAllUserNameAndUserIds(true);
        List<SelectBean> res = users.stream().map(u -> {
            return new SelectBean(u.getUserName(), u.getUserId());
        }).collect(Collectors.toList());
        return res;
    }

    @Override
    public PageData<SysUserAdapter> getUserByDeptIdsAndCreateUser(List<Long> deptIds, List<String> userIds, String query, Boolean ifExternalUser, Integer page, Integer rows) {
        PageData<SysUserAdapter> pageData = new PageData<>();
        pageData.setPage(page);
        pageData.setRows(rows);
        List<SysUserAdapter> users = sysUserMapper.getUserByDeptIdsAndCreateUserIds(deptIds, userIds, query, ifExternalUser, pageData.getBefore(), pageData.getRows());
        Integer count = sysUserMapper.getUserByDeptIdsAndCreateUserIdsCount(deptIds, userIds, query, ifExternalUser);
        pageData.setData(users);
        pageData.setTotal(count);
        pageData.setTotalPage((count + rows - 1) / rows);
        return pageData;
    }

    public DingtalkRole getRole(OapiRoleListResponse.OpenRole drole, Long groupId) {
        DingtalkRole role = new DingtalkRole();
        role.setStatus(true);
        role.setCreateTime(new Date());
        role.setGroupId(groupId);
        role.setId(drole.getId());
        role.setRoleName(drole.getName());
        role.setIfFromDingtalk(true);
        return role;
    }

    public DingtalkUser getUser(OapiUserListResponse.Userlist duser) {
        DingtalkUser user = new DingtalkUser();
        user.setUserId(duser.getUserid());
        user.setRemark(duser.getRemark());
        user.setCreateTime(new Date());
        user.setUserName(duser.getMobile());
        user.setIfDelete(false);
        user.setActive(duser.getActive());
        user.setCreateUser(0);
        user.setDingId(duser.getDingId());
        user.setAvatar(duser.getAvatar());
        user.setEmail(duser.getEmail());
        user.setHiredDate(duser.getHiredDate());
        user.setIsAdmin(duser.getIsAdmin());
        user.setIsBoss(duser.getIsBoss());
        user.setIsHide(duser.getIsHide());
        user.setIsLeader(duser.getIsLeader());
        if (!StringUtils.isBlank(duser.getJobnumber())) {
            user.setJobnumber(Long.valueOf(duser.getJobnumber()));
        }
        user.setMobile(duser.getMobile());
        user.setNickName(duser.getName());
        user.setUnionId(duser.getUnionid());
        user.setOrder(duser.getOrder());
        user.setOrgEmail(duser.getOrgEmail());
        user.setWorkPlace(duser.getWorkPlace());
        return user;
    }

    /**
     * 同步系统用户表信息
     *
     * @param updateIds
     */
    @Transactional(rollbackFor = Exception.class)
    public void loadDingTalkUpdateSysUser(List<String> updateIds) {
        updateIds.stream().forEach(
                id -> {
                    DingtalkUser dingtalkUser = dingtalkUserMapper.selectByPrimaryKey(id);
                    SysUser user = sysUserMapper.selectByPrimaryKey(id);
                    if (user == null) {
                        user = setSysUser(user, dingtalkUser);
                        sysUserMapper.insertSelective(user);
                    } else {
                        user = setSysUser(user, dingtalkUser);
                        sysUserMapper.updateByPrimaryKeySelective(user);
                    }
                }
        );
        List<String> invalidIds = dingtalkUserMapper.getInvalidUserId(updateIds);
        dingtalkUserMapper.updateDelete(invalidIds, true);
        sysUserMapper.updateDelete(invalidIds, true);

    }

    private SysUser setSysUser(SysUser user, DingtalkUser dingtalkUser) {
        if (user == null) {
            user = new SysUser();
            user.setUserId(dingtalkUser.getUserId());
            user.setCreateTime(new Date());
            user.setUserPassword(PasswordUtil.getPassword());
            user.setUserAccount(dingtalkUser.getMobile());
        }
        user.setEmail(dingtalkUser.getEmail());
        user.setIfDelete(false);
        user.setIfFromDingtalk(true);
        user.setIfSysUser(true);
        user.setMobile(dingtalkUser.getMobile());
        user.setUnionId(dingtalkUser.getUnionId());
        user.setUserName(dingtalkUser.getNickName());
        return user;
    }
}
